/**
 * 
 */
package org.jeecg.common.util;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSON;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ui.Model;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.math.BigDecimal;
import java.security.MessageDigest;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author LS
 * 共通类
 */
public class ComUtil {

	/** SLF4J日志 */
	protected static final Logger logger = LoggerFactory.getLogger(ComUtil.class);

	/**
	 * 判断是否是数字
	 * @param s 指定字符串
	 * @param startIndex 开始位置
	 * @param endIndex 结束位置
	 * @return true:数字,false:非数字
	 */
	public static boolean isNumber(String s, int startIndex, int endIndex) {
		if (s == null)
			return false;
		if (s.length() < endIndex)
			return false;
		for (int i = startIndex; i < endIndex; i++) {
			if (s.charAt(i) < '0' || s.charAt(i) > '9')
				return false;
		}
		return true;
	}
	/**
	 * 将字节数组中指定位置段的字节转为整数,如果失败就使用默认值
	 * @param bt 字节数组
	 * @param startIndex 开始索引位置
	 * @param endIndex 结束索引位置
	 * @param defaultVal 默认值
	 * @return 转换后的值
	 */
	public static int parseInt(byte[] bt, int startIndex, int endIndex, int defaultVal) {
		try {
			return Integer.parseInt(new String(bt, startIndex, endIndex - startIndex));
		} catch (Exception ex) {
			return defaultVal;
		}
	}
	/**
	 * 将字符串指定位置段转为整数,如果失败就使用默认值
	 * @param s 字符串
	 * @param startIndex 开始索引位置
	 * @param endIndex 结束索引位置
	 * @param defaultVal 默认值
	 * @return 转换后的值
	 */
	public static int parseInt(String s, int startIndex, int endIndex, int defaultVal) {
		try {
			return Integer.parseInt(s.substring(startIndex, endIndex));
		} catch (Exception ex) {
			return defaultVal;
		}
	}
	/**
	 * 将时间字符串转为日期对象 格式自动识别
	 * 
	 * @param text 指定格式时间字符串
	 * @return 日期.转换失败返回null
	 */
	public static Date parseDate(String text) {
		try {
			String format = null;
			String format1 = "yyyyMMddHHmmss";
			String format2 = "yyyy-MM-dd HH:mm:ss";
			String format3 = "yyyy/MM/dd HH:mm:ss";
			if (text.indexOf('-') > 0) {
				format = format2.substring(0, text.length());
			} else if (text.indexOf('/') > 0) {
				format = format3.substring(0, text.length());
			} else {
				format = format1.substring(0, text.length());
			}
			return new SimpleDateFormat(format).parse(text);
		} catch (Exception ex) {
			return null;
		}
	}
	/**
	 * 将字节数组指定位置段的字节转为字符串
	 * @param bt 字节数组
	 * @param startIndex 开始索引位置
	 * @param endIndex 结束索引位置
	 * @param charsetName 编码
	 * @return 转换后的值
	 */
	public static String toStr(byte[] bt, int startIndex, int endIndex, String charsetName) throws RuntimeException {
		if (bt == null || bt.length < endIndex)
			return null;
		try {
			return new String(bt, startIndex, endIndex - startIndex, charsetName);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
	/**
	 * 将数字转为字符串
	 * @param i 指定数字
	 * @param len 规定长度
	 * @return 转换后的值
	 */
	public static String toStr(long i, int len) throws RuntimeException {
		String s = String.format("%0" + len + "d", i);
		if (s.length() > len)
			s = s.substring(s.length() - len);
		return s;
	}
	/**
	 * 截取字符串
	 * @param str 指定字符串
	 * @param len 规定长度
	 * @return 转换后的值
	 */
	public static String cut(String str, int len) {
		if (str == null)
			return str;
		if (str.length() < len)
			return str;
		return str.substring(0, len);
	}
	
	public static boolean isEmpty(String s) {
		return s == null || s.isEmpty();
	}
	
	public static String sysDate(int i) {
		return sysDate(i, "yyyyMMdd");
	}
	
	public static String sysDate(int i, String format) {
		Calendar c = Calendar.getInstance();
		if (i != 0) {
			c.add(Calendar.DAY_OF_MONTH, i);
		}
		return new SimpleDateFormat(format).format(c.getTime());
	}

	public static String sysDateTime(String format) throws RuntimeException {
		return sysDate(0, format);
	}

	public static String sysDateTime() throws RuntimeException {
		return sysDateTime("yyyyMMddHHmmss");
	}

	public static String sysDateTime(int i) throws RuntimeException {
		Calendar c = Calendar.getInstance();
		if (i != 0) {
			c.add(Calendar.SECOND, i);
		}
		return new SimpleDateFormat("yyyyMMddHHmmss").format(c.getTime());
	}

	public static String sysDate() throws RuntimeException {
		return sysDateTime("yyyyMMdd");
	}

	/**
	 * 判断该日期是否是该月的最后一天
	 * @param date
	 * 需要判断的日期
	 * @return
	 */
	public static boolean isLastDayOfMonth(Date date) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		return calendar.get(Calendar.DAY_OF_MONTH) == calendar
				.getActualMaximum(Calendar.DAY_OF_MONTH);
	}

	public static Date addTime(Date d, int field, int amount) throws RuntimeException {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		if (amount != 0) {
			c.add(field, amount);
		}
		return c.getTime();
	}

	public static String dateTimeFmt(String dt, String outFmt) throws RuntimeException {
		try {
			return dateTimeFmt(parseDate(dt), outFmt);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	public static String dateTimeFmt(String dt, String inFmt, String outFmt) throws RuntimeException {
		try {
			return dateTimeFmt(new SimpleDateFormat(inFmt).parse(dt), outFmt);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	public static String dateTimeFmt(Date d, String outFmt) throws RuntimeException {
		try {
			return new SimpleDateFormat(outFmt).format(d);
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}

	/**
	 * 返回指定日期的星期几
	 * @param d 日期
	 * @return 0到6分别代表星期天到星期六
	 */
	public static int getDayOfWeek(Date d) {
		Calendar c = Calendar.getInstance();
		c.setTime(d);
		return c.get(Calendar.DAY_OF_WEEK) - 1;
	}
	
	/**
	 * 求两个日期的间隔天数
	 * @param d1 开始日
	 * @param d2 结束日
	 * @return 天数(周天数)
	 */
	public static int diffDays(Date d1, Date d2) {
		return (int)((d2.getTime() - d1.getTime()) / (1000 * 60 * 60 * 24));
	}

	public static String md5(String s) throws RuntimeException {
		char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

		try {
			byte[] btInput = s.getBytes();
			// 获得MD5摘要算法的 MessageDigest 对象
			MessageDigest mdInst = MessageDigest.getInstance("MD5");
			// 使用指定的字节更新摘要
			mdInst.update(btInput);
			// 获得密文
			byte[] md = mdInst.digest();
			// 把密文转换成十六进制的字符串形式
			int j = md.length;
			char str[] = new char[j * 2];
			int k = 0;
			for (int i = 0; i < j; i++) {
				byte byte0 = md[i];
				str[k++] = hexDigits[byte0 >>> 4 & 0xf];
				str[k++] = hexDigits[byte0 & 0xf];
			}
			return new String(str);
		} catch (Exception e) {
			logger.error("MD5出错", e);
			throw new RuntimeException(e);
		}
	}

	public static String getFilename(File file) {
		String fn = file.getName();
		int idx = fn.lastIndexOf('.');
		if (idx < 0) return fn;
		return fn.substring(0, idx);
	}
	

	private static final int timeout = 90 * 1000; // 90 seconds
	public static final RequestConfig requestConfig = RequestConfig.custom()
	        .setConnectTimeout(timeout)
	        .setConnectionRequestTimeout(timeout)
	        .setSocketTimeout(timeout).build();
	
	public static String httpPost(String url, Map<String, String> body) throws RuntimeException {
		// HttpClient
		try (CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
				.build()) {

			HttpPost httpPost = new HttpPost(url);
			// 创建参数
	        List<NameValuePair> nvps = new ArrayList<NameValuePair>();
	        body.entrySet().forEach(entry -> {
	        	nvps.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
	        }); 
	        httpPost.setEntity(new UrlEncodedFormEntity(nvps, "UTF8"));

			// post请求
			try (CloseableHttpResponse httpResponse = closeableHttpClient.execute(httpPost)) {
				int status = httpResponse.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity httpEntity = httpResponse.getEntity();
                    return httpEntity != null ? EntityUtils.toString(httpEntity, "UTF8") : null;
                } else {
                    throw new RuntimeException("Unexpected response status: " + httpResponse.getStatusLine());
                }
			}
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
	public static String httpPost(String url, String body) throws RuntimeException {
		// HttpClient
		try (CloseableHttpClient closeableHttpClient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
				.build()) {

			HttpPost httpPost = new HttpPost(url);
			// 创建参数
			StringEntity entity = new StringEntity(body, "UTF-8");
			
			httpPost.setEntity(entity);

			// post请求
			try (CloseableHttpResponse httpResponse = closeableHttpClient.execute(httpPost)) {
				int status = httpResponse.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity httpEntity = httpResponse.getEntity();
                    return httpEntity != null ? EntityUtils.toString(httpEntity, "UTF8") : null;
                } else {
                    throw new RuntimeException("Unexpected response status: " + httpResponse.getStatusLine());
                }
			}
		} catch (Exception ex) {
			throw new RuntimeException(ex);
		}
	}
	public static JSONObject doPost(String url, String json, String key) throws Exception {
		CloseableHttpClient httpclient = HttpClientBuilder.create().build();
		HttpPost post = new HttpPost(url);
		JSONObject response = null;
		StringEntity s = new StringEntity(json);
		s.setContentEncoding("UTF-8");
		s.setContentType("application/json");//发送json数据需要设置contentType
		post.setEntity(s);
		HttpResponse res = httpclient.execute(post);
		if(res.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
			String result = EntityUtils.toString(res.getEntity());// 返回json格式：
			logger.info("下单返回json:{}", result);
			String cipher = Sm4Util.decryptEcb(key, result);
			response = JSONObject.parseObject(cipher);
		}
		return response;
	}
	public static String httpGet(String url) throws Exception {

		try (CloseableHttpClient httpclient = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig)
				.build()) {

			HttpGet httpget = new HttpGet(url);

			// post请求
			try (CloseableHttpResponse httpResponse = httpclient.execute(httpget)) {
				int status = httpResponse.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity httpEntity = httpResponse.getEntity();
                    return httpEntity != null ? EntityUtils.toString(httpEntity, "UTF8") : null;
                } else {
                    throw new RuntimeException("Unexpected response status: " + httpResponse.getStatusLine());
                }
			}
		}catch (Exception ex){
			throw new RuntimeException(ex);
		}
	}

    /**
     * unicode转中文
     * @param theString
     * @return
     */
	public static String decodeUnicode(String theString) {
		char aChar;
		int len = theString.length();
		StringBuffer outBuffer = new StringBuffer(len);
		for (int x = 0; x < len;) {
			aChar = theString.charAt(x++);
			if (aChar == '\\') {
				aChar = theString.charAt(x++);
				if (aChar == 'u') {
					// Read the xxxx
					int value = 0;
					for (int i = 0; i < 4; i++) {
						aChar = theString.charAt(x++);
						switch (aChar) {
						case '0':
						case '1':
						case '2':
						case '3':
						case '4':
						case '5':
						case '6':
						case '7':
						case '8':
						case '9':
							value = (value << 4) + aChar - '0';
							break;
						case 'a':
						case 'b':
						case 'c':
						case 'd':
						case 'e':
						case 'f':
							value = (value << 4) + 10 + aChar - 'a';
							break;
						case 'A':
						case 'B':
						case 'C':
						case 'D':
						case 'E':
						case 'F':
							value = (value << 4) + 10 + aChar - 'A';
							break;
						default:
							throw new IllegalArgumentException("Malformed   \\uxxxx   encoding.");
						}
					}
					outBuffer.append((char) value);
				} else {
					if (aChar == 't')
						aChar = '\t';
					else if (aChar == 'r')
						aChar = '\r';
					else if (aChar == 'n')
						aChar = '\n';
					else if (aChar == 'f')
						aChar = '\f';
					outBuffer.append(aChar);
				}
			} else
				outBuffer.append(aChar);
		}
		return outBuffer.toString();
	}
	/**
	 * 数字转16进制
	 * @param n
	 * @return
	 */
    public static String intToHex(int n){
        char[] ch = new char[20];
        int nIndex = 0;
        while ( true ){
            int m = n/16;
            int k = n%16;
            if ( k == 15 )
                ch[nIndex] = 'F';
            else if ( k == 14 )
                ch[nIndex] = 'E';
            else if ( k == 13 )
                ch[nIndex] = 'D';
            else if ( k == 12 )
                ch[nIndex] = 'C';
            else if ( k == 11 )
                ch[nIndex] = 'B';
            else if ( k == 10 )
                ch[nIndex] = 'A';
            else
                ch[nIndex] = (char)('0' + k);
            nIndex++;
            if ( m == 0 )
                break;
            n = m;
        }
        StringBuffer sb = new StringBuffer();
        sb.append(ch, 0, nIndex);
        sb.reverse();
        String strHex = new String("0");
        strHex += sb.toString();
        return strHex;
    }
    
    private static int __sn_seq = 0;
    /**
     * 创建订单编号
     * @return 订单编号
     */
    public static String createSn(char tp) {
    	return createSn(tp + "", 4);
    }
    /**
     * 创建订单编号
     * @return 订单编号
     */
    public static String createSn(String tp, int w) {
    	if (__sn_seq > 9999) __sn_seq = 0;
    	String sn = ComUtil.sysDateTime() + tp + ComUtil.toStr(__sn_seq++, w);
    	return sn;
    }
	/**
	 * 创建发票订单编号
	 * @return 订单编号
	 */
	public static String createInvoiceSn(String tp, int w) {
		if (__sn_seq > 9999) __sn_seq = 0;
		String sn = tp + ComUtil.sysDateTime("yyyyMMddHHmm") + ComUtil.toStr(__sn_seq++, w);
		return sn;
	}
    /**
     * 创建订单编号
     * @return 订单编号
     */
    public static String createJsSn() {
    	if (__sn_seq > 9999) __sn_seq = 0;
    	String sn = ComUtil.sysDateTime() + "JS" + ComUtil.toStr(__sn_seq++, 3);
    	return sn;
    }
    //十六进制转字节流
    public static byte[] hex2byte(String hex) {
    	if (isEmpty(hex)) return null;
        hex = hex.replace(" ", "");
        if (hex.length() % 2 != 0) return null;
        hex = hex.toLowerCase();//F1  -->  f1
        
        if (!hex.matches("^([0-9a-f]{2})+$"))
        {
            return null;
        }
        byte[] bt = new byte[hex.length() / 2];
        int pos = 0;
        Pattern reg = Pattern.compile("([0-9a-f]{2})");
        Matcher m = reg.matcher(hex);
        while (m.find())
        {
        	bt[pos++] = (byte)Integer.parseInt(m.group(1), 16);
        }
    	return bt;
    }
    //字节流转十六进制
    public static String byte2hex(byte[] bt) {
    	if (bt == null || bt.length == 0) return null;
    	StringBuffer sb = new StringBuffer(bt.length * 2);
    	int a;
    	for (int i = 0; i < bt.length; i++) {
    		a = bt[i];
    		sb.append(String.format("%02x", 0xff & a));
    	}
    	return sb.toString();
    }
    /**
     * DES加密
     * @param decBytes 待加密字节组
     * @param key 密钥,8字节
     */
	public static byte[] encryptDes(byte[] decBytes, byte[] keyBytes) {
		try {
			SecretKey secretKey = new SecretKeySpec(keyBytes, "DES");
			Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
			// encrypt
			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
			byte[] decryptPlainText = cipher.doFinal(decBytes);
			return decryptPlainText;
		} catch (Exception ex) {
			logger.error("DES加密失败", ex);
			throw new RuntimeException(ex);
		}
	}
    /**
     * DES解密
     * @param decBytes 待解密字节组
     * @param key 密钥,8字节
     */
	public static byte[] decryptDes(byte[] decBytes, byte[] keyBytes) {
		try {
			SecretKey secretKey = new SecretKeySpec(keyBytes, "DES");
			Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding");
			// decrypt
			cipher.init(Cipher.DECRYPT_MODE, secretKey);
			byte[] decryptPlainText = cipher.doFinal(decBytes);
			return decryptPlainText;
		} catch (Exception ex) {
			logger.error("DES解密失败", ex);
			throw new RuntimeException(ex);
		}
	}
    /**
     * 3DES加密
     * @param decBytes 待加密字节组
     * @param key 密钥,24字节
     */
	public static byte[] encrypt3Des(byte[] decBytes, byte[] keyBytes) {
		try {
			SecretKey secretKey = new SecretKeySpec(keyBytes, "DESede");
			Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
			//Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
			//Cipher cipher = Cipher.getInstance("DESede/ECB/ZerosPadding");
			// encrypt
			cipher.init(Cipher.ENCRYPT_MODE, secretKey);
			byte[] decryptPlainText = cipher.doFinal(decBytes);
			return decryptPlainText;
		} catch (Exception ex) {
			logger.error("DES加密失败", ex);
			throw new RuntimeException(ex);
		}
	}
    /**
     * DES解密
     * @param decBytes 待解密字节组
     * @param key 密钥,8字节
     */
	public static byte[] decrypt3Des(byte[] decBytes, byte[] keyBytes) {
		try {
			SecretKey secretKey = new SecretKeySpec(keyBytes, "DESede");
			Cipher cipher = Cipher.getInstance("DESede/ECB/NoPadding");
			//Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
			// decrypt
			cipher.init(Cipher.DECRYPT_MODE, secretKey);
			byte[] decryptPlainText = cipher.doFinal(decBytes);
			return decryptPlainText;
		} catch (Exception ex) {
			logger.error("DES解密失败", ex);
			throw new RuntimeException(ex);
		}
	}

	/**
	 * 放入session
	 * @param session
	 * @param key
	 * @param val
     * @return
     */
	public static Object getOrSetSession(HttpSession session, String key, Object val) {
		if (val != null) {
			session.setAttribute(key, val);
			return val;
		} else {
			val = session.getAttribute(key);
		}
		return val;
	}

	/**
	 * 获取时间戳（秒）
	 * @param date
	 * @return
	 */
	public static String getSecondTimestamp(Date date){
		if (null == date) {
			return null;
		}
		String timestamp = String.valueOf(date.getTime());
		int length = timestamp.length();
		if (length > 3) {
			return timestamp.substring(0,length-3);
		} else {
			return null;
		}
	}

	
	/**
	 * 添加Model消息
	 * @param messages 消息
	 */
	public static void addMessage(Model model, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		model.addAttribute("message", sb.toString());
	}
	
	/**
	 * 添加Flash消息
     * @param messages 消息
	 */
	public static void addMessage(RedirectAttributes redirectAttributes, String... messages) {
		StringBuilder sb = new StringBuilder();
		for (String message : messages){
			sb.append(message).append(messages.length>1?"<br/>":"");
		}
		redirectAttributes.addFlashAttribute("message", sb.toString());
	}

	public static final String CURRENCY_FEN_REGEX = "\\-?[0-9]+";

	/**
	 * 分转元
	 * @param amount
	 * @return
	 * @throws Exception
     */
	public static String changeF2Y(String amount) throws Exception
	{
		if (!amount.matches(CURRENCY_FEN_REGEX)) {
			throw new Exception("金额格式有误");
		}
		return BigDecimal.valueOf(Long.valueOf(amount)).divide(new BigDecimal(100)).toString();
	}


	/**
	 * 正整数校验
	 * @param number
	 * @return
	 */
	public static boolean isNumber(String number){
		boolean flag = false;
		try {
			if (StringUtils.isBlank(number)){
				return false;
			}
			String pattern = "^[1-9]\\d*$";
			flag = number.matches(pattern);
		}catch (Exception e){
			logger.error("正整数校验异常", e);
			throw new RuntimeException(e);
		}
		return flag;
	}


	/**
	 * 车牌号码校验
	 * @param plateNumber
	 * @return
	 */
	public static boolean isPlateNumber(String plateNumber){
		boolean flag = true;
		try {
			if (StringUtils.isBlank(plateNumber)){
				return false;
			}
			if (plateNumber.length() < 7 || plateNumber.length() > 8){
				logger.error("车牌长度不符合要求：{}，长度:{}",plateNumber, plateNumber.length());
				return false;
			}
			if (plateNumber.contains("o") || plateNumber.contains("O") || plateNumber.contains("i") || plateNumber.contains("I")){
				logger.error("车牌输入字符错误：{}",plateNumber);
				return false;
			}
			//String pattern = "^([京津晋冀蒙辽吉黑沪苏浙皖闽赣鲁豫鄂湘粤桂琼渝川贵云藏陕甘青宁新][ABCDEFGHJKLMNPQRSTUVWXY][1-9DF][1-9ABCDEFGHJKLMNPQRSTUVWXYZ]\\d{3}[1-9DF]|[京津晋冀蒙辽吉黑沪苏浙皖闽赣鲁豫鄂湘粤桂琼渝川贵云藏陕甘青宁新][ABCDEFGHJKLMNPQRSTUVWXY][\\dABCDEFGHJKLNMxPQRSTUVWXYZ]{5})$";
			//String pattern = "^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[ADFG])|([ADFG]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$";
			//String pattern = "^(([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z](([0-9]{5}[DF])|([DF]([A-HJ-NP-Z0-9])[0-9]{4})))|([京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领][A-Z][A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳使领]))$";
			//flag = plateNumber.matches(pattern);
		}catch (Exception e){
			logger.error("车牌校验异常", e);
			throw new RuntimeException(e);
		}
		return flag;
	}


	/**
	 * 从List<A> copy到List<B>
	 *
	 * @param <T>
	 * @param list
	 * @param clazz
	 * @return
	 */
	public static <T> List<T> copy(List<?> list, Class<T> clazz) {
		String oldOb = JSON.toJSONString(list);
		return JSON.parseArray(oldOb, clazz);
	}
}

